package de.herzog.bbp.view.javafx;

import java.util.ArrayList;
import java.util.List;

import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.EventHandler;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import de.herzog.bbp.view.bean.AbstractBean;

public class EditNextColumnOnTabHandler<S extends AbstractBean, T> implements EventHandler<KeyEvent> {

	private TableView<S> tableView;
	private int firstColumnIndexToEdit;
	private TableCell<S, T> tableCell;
	private List<TableColumn<S, ?>> editableColumns;

	public EditNextColumnOnTabHandler(TableView<S> tableView) {
		this(tableView, 0);
	}

	public EditNextColumnOnTabHandler(TableView<S> tableView, int firstColumnIndexToEdit) {
		super();
		this.tableView = tableView;
		this.firstColumnIndexToEdit = firstColumnIndexToEdit;
		this.editableColumns = getEditableColumns();
	}

	private List<TableColumn<S, ?>> getEditableColumns() {
		if (editableColumns == null) {
			editableColumns = new ArrayList<TableColumn<S, ?>>();
			for (TableColumn<S, ?> tableColumn : tableView.getColumns()) {
				addEditableColumn(tableColumn);
			}
		}
		return editableColumns;
	}

	private void addEditableColumn(TableColumn<S, ?> parentColumn) {
		if (parentColumn.getColumns().isEmpty()) {
			// This is a leaf, add it if editable.
			if (parentColumn.isEditable()) {
				editableColumns.add(parentColumn);
			}
		} else {
			// This is an inner node, add all its children
			for (TableColumn<S, ?> childColumn : parentColumn.getColumns()) {
				addEditableColumn(childColumn);
			}
		}
	}

	public void setTableCell(TableCell<S, T> tableCell) {
		this.tableCell = tableCell;
	}

	public void editNextColumn(int direction) {
		int currColumnIndex = getEditableColumns().indexOf(tableCell.getTableColumn());
		int nextColumnIndex = currColumnIndex + direction;
		int currRowIndex = tableCell.getTableRow().getIndex();
		int nextRowIndex = currRowIndex;
		if (nextColumnIndex < 0) {
			nextColumnIndex = editableColumns.size() - 1;
			nextRowIndex -= 1;
		}
		if (nextColumnIndex > editableColumns.size() - 1) {
			nextColumnIndex = firstColumnIndexToEdit;
			nextRowIndex += 1;
		}
		if (nextRowIndex < 0) {
			nextColumnIndex = 0;
			nextRowIndex = 0;
		}
		if (nextRowIndex >= tableView.getItems().size()) {
			S oldBean = tableView.getItems().get(currRowIndex);
			@SuppressWarnings("unchecked")
			S newBean = (S) oldBean.clone();
			@SuppressWarnings("unchecked")
			ObservableList<S> items = (ObservableList<S>) ((FilteredList<S>) tableView.getItems()).getSource();
            items.add(newBean);
		}
		if (currRowIndex != nextRowIndex) {
			tableView.getSelectionModel().select(nextRowIndex);
			tableView.scrollTo(nextRowIndex);
		}
		final int row = nextRowIndex;
		final int col = nextColumnIndex;
		Platform.runLater(() -> tableView.edit(row, getEditableColumns().get(col)));
	}

	@Override
	public void handle(KeyEvent keyEvent) {
		if (keyEvent.getCode() == KeyCode.ENTER) {
			editNextColumn(1);
		} else if (keyEvent.getCode() == KeyCode.TAB) {
			editNextColumn(keyEvent.isShiftDown() ? -1 : 1);
		}
	}
}
